using Sandia.MVCFramework.Common;
using System;
using System.Collections.Generic;
using System.Reflection;
using System.Text;

namespace Sandia.MVCFramework.Request
{
    // Test notes:
    // 1) try to use a type 'T' that does NOT inherit from IRequest
    // 2) pass in an empty parameter factory list
    // 3) use a type 'T' that does not have a default (no parameters) constructor
    //      or that constructor is private
    // 4) Create a mis-match between the 'Type' and the corresponding
    //      'IRequestParameterFactory' - not sure what will happen
    // 5) Create a normal parameter factory list, then check the request
    //      to ensure that all of those parameters were created
 

    /// <summary>
    /// A class used to generically create IRequest.
    /// </summary>
    public class StandardRequestFactory : IRequestFactory
    {
        /// <summary>
        /// The internal request.
        /// </summary>
        private IRequest request;

        /// <summary>
        /// The factory to make all the needed parameters.
        /// </summary>
        private StandardRequestParameterFactory parameterFactory;

        /// <summary>
        /// Constructor for StandardRequestFactory.
        /// </summary>
        public StandardRequestFactory()
        {
            this.parameterFactory =
                new StandardRequestParameterFactory();
        }

        #region IRequestFactory Members

        /// <summary>
        /// Create a request using the given parameters.
        /// </summary>
        /// <param name="requestType">The type of request to create.</param>
        public void CreateRequest(
            Type requestType)
        {
            // Make sure that this is an IRequest.
            //
            if (!typeof(IRequest).IsAssignableFrom(requestType))
            {
                LoggingTools.SendToLog(
                    requestType.ToString() +
                    " does not inherit from IRequest.",
                    LoggingCategories.ERROR,
                    100);
                return;
            }

            // Create the request

            // In order to instantiate something of type 'requestType'
            // we have to use reflection to determine if the
            // type has the correct constructor.
            //
            ConstructorInfo requestConstructorInfo =
                requestType.GetConstructor(Type.EmptyTypes);

            // If type 'requestType' does not have an empty constructor
            //
            if (requestConstructorInfo == null)
            {
                LoggingTools.SendToLog(
                    "Type " +
                    requestType.FullName +
                    " does not have an empty (default) constructor.",
                    LoggingCategories.ERROR,
                    100);
                return;
            }

            // Actually call the constructor using reflection
            //
            this.request =
                (IRequest)requestConstructorInfo.Invoke(new object[0]);
        }

        /// <summary>
        /// Adds a parameter of the given type with the given data to the
        /// parameter.
        /// </summary>
        /// <param name="parameterType">The type of parameter to add.</param>
        /// <param name="data">The data to put in the parameter.</param>
        public void SetParameter(
            Type parameterType, 
            object data)
        {
            // Ensure that the request has been created
            //
            if (this.request == null)
            {
                LoggingTools.SendToLog(
                    "The request has not yet been created - cannot add a parameter.",
                    LoggingCategories.ERROR,
                    100);
                return;
            }

            // Create the parameter using the factory member variable
            //
            IRequestParameter parameter = parameterFactory.CreateRequestParameter(parameterType, data);

            // The syntax looks strange, but this adds the parameter to the request
            //
            request[parameter.Name] = parameter;
        }

        /// <summary>
        /// Set the requester identifier and return the created request.
        /// </summary>
        /// <param name="requesterID">the identifier of the requester</param>
        /// <returns>the created request</returns>
        public IRequest GetRequest(
            string requesterID)
        {
            this.request.RequesterID = requesterID;
            return this.request;
        }

        #endregion
    }
}
